package com.kullachi.jmx.d3;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import javax.management.InstanceNotFoundException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerNotification;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.media.j3d.Transform3D;
import javax.vecmath.Vector3d;

import com.sun.j3d.utils.universe.SimpleUniverse;

public class MBeanServerConnectionAdapter implements NotificationListener {
	private MBeanServerConnection serverConnection;
	private SimpleUniverse simpleUniverse;

	int serviceCount =0;
	
	private List<String> beanNames = new ArrayList<String>();
	private List<Vector3d> positions = new ArrayList<Vector3d>();
	
	public MBeanServerConnectionAdapter(JMXConnector connector,SimpleUniverse u) throws InstanceNotFoundException, MalformedObjectNameException, NullPointerException, IOException{
		this.serverConnection 	= connector.getMBeanServerConnection();;
		this.simpleUniverse		= u;
		serverConnection.addNotificationListener(new ObjectName("JMImplementation:type=MBeanServerDelegate"), this, null, null);
		connector.addConnectionNotificationListener(this, null, null);
		positions.add(new Vector3d(0.0, 0.0, 0.0));
		positions.add(new Vector3d(-0.3, 0.0, 0.0));
		positions.add(new Vector3d(0.0, -0.3, 0.0));
		positions.add(new Vector3d(0.3, 0.0, 0.0));
		positions.add(new Vector3d(0.0, 0.3, 0.0));
		positions.add(new Vector3d(0.2, 0.8, 0.0));
		positions.add(new Vector3d(0.8, 0.3, 0.0));
	}
	
	public void adapt(String name) throws Exception{
		if(!beanNames.contains(name))
			beanNames.add(name);
		Set<ObjectName> mBeans = new TreeSet<ObjectName>(serverConnection.queryNames(new ObjectName(name+"*"), null));
		for (ObjectName bean : mBeans) {
			 Transform3D 	t 		= new Transform3D();
			 t.set(0.08,positions.get(serviceCount++));
			 MBean3D bean3D		=  new MBean3D(false,false,t,null,bean);
			 try{
				 MBeanInfo 				info 			= serverConnection.getMBeanInfo(bean);
				 MBeanAttributeInfo[] 	attributeInfo 	= info.getAttributes();
				 for(MBeanAttributeInfo attInfo: attributeInfo){
					 bean3D.addAttribute(new MBeanAttributeInfo3D(attInfo),serverConnection.getAttribute(bean, attInfo.getName()));
				 }
				 MBeanOperationInfo infoOper[] =  info.getOperations();
				 for(MBeanOperationInfo op:infoOper){
					 bean3D.addOperation(new MBeanOperationInfo3D(op));
				 }
				 serverConnection.addNotificationListener(bean, bean3D, null, null);
			 }catch(Throwable th){
				 th.printStackTrace();
			 }
			 simpleUniverse.addBranchGraph(bean3D);
		}
	}

	@Override
	public void handleNotification(Notification notification, Object handback) {
		  if(notification.getType().equals("JMX.mbean.registered")){
			  MBeanServerNotification beanNotification = (MBeanServerNotification)notification;
			  ObjectName added =  beanNotification.getMBeanName();
			  for(String name: beanNames){
				  if (added.getCanonicalName().startsWith(name)) {
					Transform3D t = new Transform3D();
					t.set(0.08, positions.get(serviceCount++));

					MBean3D bean3D = new MBean3D(false, false, t, null, added);
					try {
						MBeanInfo info = serverConnection.getMBeanInfo(added);
						MBeanAttributeInfo[] attributeInfo = info
								.getAttributes();
						for (MBeanAttributeInfo attInfo : attributeInfo) {
							bean3D.addAttribute(new MBeanAttributeInfo3D(
									attInfo), serverConnection.getAttribute(
									added, attInfo.getName()));
						}
						MBeanOperationInfo infoOper[] = info.getOperations();
						for (MBeanOperationInfo op : infoOper) {
							bean3D.addOperation(new MBeanOperationInfo3D(op));
						}
						serverConnection.addNotificationListener(added, bean3D, null, null);	
					} catch (Throwable th) {
						th.printStackTrace();
					}
					simpleUniverse.addBranchGraph(bean3D);
				}
			  }
		  }else if(notification.getType().equals("JMX.mbean.unregistered")){
			  MBeanServerNotification beanNotification = (MBeanServerNotification)notification;
			  //TODO
		  }
		
	}
	
}
